#!/usr/bin/env python3

import sys
import time
import socket
from scapy.all import *
from scapy.layers.inet import IP, ICMP
from scapy.layers.l2 import Ether

# 自定义源路由头部
class SourceRouting(Packet):
    name = "SourceRouting"
    fields_desc = [
        ByteField("path_len", 0),
        ByteField("next_port", 0)
    ]

# 绑定到以太网类型 0x1234
bind_layers(Ether, SourceRouting, type=0x1234)
# 或者绑定到IP协议号 0xFD
bind_layers(IP, SourceRouting, proto=0xFD)

def send_source_routing_packet():
    """发送源路由测试包"""
    print("发送源路由测试包...")

    # 方法1: 直接使用以太网帧
    eth_pkt = Ether(dst="00:00:00:00:01:02", src="00:00:00:00:01:01", type=0x1234)
    src_route_pkt = SourceRouting(path_len=3, next_port=2)  # 路径长度3，下一端口2

    # 添加一些载荷
    payload = "Source Routing Test Payload"
    full_pkt = eth_pkt / src_route_pkt / Raw(load=payload.encode())

    # 发送数据包
    sendp(full_pkt, iface="h1-eth0", verbose=1)

    print("源路由数据包已发送")

def send_ip_with_source_routing():
    """发送IP包携带源路由头部"""
    print("发送IP包携带源路由头部...")

    # 方法2: 使用IP包携带源路由
    ip_pkt = IP(dst="10.0.0.2", src="10.0.0.1", proto=0xFD)
    src_route_pkt = SourceRouting(path_len=4, next_port=3)
    payload = "IP with Source Routing Test"

    full_pkt = ip_pkt / src_route_pkt / Raw(load=payload.encode())

    # 发送数据包
    send(full_pkt, verbose=1)

    print("IP源路由数据包已发送")

def test_connectivity():
    """测试基本连通性"""
    print("测试基本连通性...")

    # 发送ICMP ping包
    ping_pkt = IP(dst="10.0.0.2")/ICMP()
    response = sr1(ping_pkt, timeout=2, verbose=1)

    if response:
        print("✓ 连通性测试通过")
        return True
    else:
        print("✗ 连通性测试失败")
        return False

def main():
    """主函数"""
    print("=== 源路由测试开始 ===")

    # 测试基本连通性
    if not test_connectivity():
        print("请先确保基础网络连通性")
        return

    # 发送源路由包
    time.sleep(1)
    send_source_routing_packet()

    time.sleep(1)
    send_ip_with_source_routing()

    print("=== 源路由测试完成 ===")
    print("请在交换机端口上使用 tcpdump 抓包验证源路由头部")

if __name__ == "__main__":
    main()
